﻿using Microsoft.AspNetCore.Mvc;
using PMS.Core.Configuration.CommonEnumConfigs;
using PMS.Core.Utils;
using PMS.Data.Entities.SystemModules;
using PMS.Services.EntityServices.Customers;
using PMS.Services.EntityServices.Stores;
using PMS.Services.EntityServices.SystemModules;
using PMS.Services.SharedKernel;
using PMS.Services.Utils.Security;
using PMS.Web.Factories.SystemModules;
using PMS.Web.Framework.Controllers;
using PMS.Web.Framework.Mvc.Filters;
using PMS.Web.Models;
using PMS.Web.Models.Stores;
using PMS.Web.Models.SystemModules;
using System;
using System.Collections.Generic;
using System.Linq;

namespace PMS.Web.Controllers.WebApi.AdminArea.SystemModules
{
    [AuthorizeCustomer(CustomerAuthorizeType.Admin)]
    public class SystemModuleWebApi : BaseApiController
    {
        #region Fields
        private readonly IWorkContext _workContext;
        private readonly IStoreContext _storeContext;
        private readonly IStoreService _storeService;
        private readonly ICustomerService _customerService;
        private readonly IPermissionService _permissionService;
        private readonly IStoreMappingService _storeMappingService;
        private readonly ISystemModuleService _systemModuleService;
        private readonly ISystemModuleModleFactory _systemModuleModleFactory;
        #endregion

        #region Ctor
        public SystemModuleWebApi(IWorkContext workContext,
            IStoreContext storeContext,
            IStoreService storeService,
            ICustomerService customerService,
            IPermissionService permissionService,
            IStoreMappingService storeMappingService,
            ISystemModuleService systemModuleService,
            ISystemModuleModleFactory systemModuleModleFactory)
        {
            _workContext = workContext;
            _storeContext = storeContext;
            _storeService = storeService;
            _customerService = customerService;
            _permissionService = permissionService;
            _storeMappingService = storeMappingService;
            _systemModuleService = systemModuleService;
            _systemModuleModleFactory = systemModuleModleFactory;
        }
        #endregion

        #region Utils
        protected string ConvertFromArray(IEnumerable<int> idArray)
        {
            if (!(idArray?.Any() ?? false)) return string.Empty;
            idArray.ToList().Sort((x, y) => x.CompareTo(y));
            return string.Join(',', idArray.Select(id => id.ToString()).ToArray());
        }

        protected (bool CheckResult, int[] CanceledBtnIds) CheckAssignedButtonsChange(int moduleId, IList<int> assignedbtnIds)
        {
            var moduleModel = _systemModuleModleFactory.GetSystemModuleModel(moduleId);
            if (moduleModel == null) return (false, new int[] { });
            else if (moduleModel.OpenMode == LinkOpenMode.None)
                return (false, new int[] { });
            var allRolesModuleMappings = _systemModuleService.GetSystemModuleCustomerRoleMappingsBySystemModuleId(moduleId);
            if (allRolesModuleMappings?.Any() ?? false)
            {
                var roleModuleAuthedBtnIds = allRolesModuleMappings.SelectMany(mp => mp.AuthorizedButtons).Distinct().ToList();
                if (CommonHelper.ArraysEqual(roleModuleAuthedBtnIds.ToArray(), assignedbtnIds.ToArray()))
                    return (false, new int[] { });
                else if (roleModuleAuthedBtnIds.Except(assignedbtnIds)?.Any() ?? false)
                    return (true, roleModuleAuthedBtnIds.Except(assignedbtnIds).ToArray());
                else if (assignedbtnIds.Except(roleModuleAuthedBtnIds)?.Any() ?? false)
                    return (false, new int[] { });
            }
            return (false, new int[] { });
        }
        #endregion

        #region Methods
        /// <summary>
        /// 加载后台系统模块菜单
        /// </summary>
        /// <param name="all">
        ///    False : 默认false,按用户所有角色权限加载系统菜单 用于后台主页菜单数据加载
        ///    True : 当前Store所有菜单数据加载，用于系统模块编辑页加载父级菜单
        /// </param>
        /// <returns></returns>
        [HttpGet(WebApiRouteConfig.LoadSystemMenus)]
        public IActionResult LoadSystemMenusApi(bool all = false)
        {
            try
            {
                var adminUser = _workContext.CurrentCustomer;
                var curStore = _storeContext.CurrentStore;
                var menus = _systemModuleModleFactory.PrepareSystemMenuModels(curStore.Id, adminUser.Id, all);
                return SuccessJson("", menus, true);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 系统模块管理功能获取所有当前店铺下的模块数据
        /// </summary>
        /// <returns></returns>
        [HttpGet(WebApiRouteConfig.GetSystemModuleList)]
        public IActionResult GetSystemModuleModelsListApi()
        {
            try
            {
                var curStore = _storeContext.CurrentStore;
                var allStores = _storeService.GetAllStores();
                return SuccessJson("", new
                {
                    ModuleModels = _systemModuleModleFactory.PrepareAllSystemModuleModels(curStore.Id),
                    ModuleButtons = _systemModuleModleFactory.PrepareAllModuleButtons(),
                    Stores = allStores.Select(entity => new StoreSelectModel()
                    {
                        Id = entity.Id,
                        Name = entity.Name,
                        Url = entity.Url,
                        Order = entity.DisplayOrder,
                        Selected = false,
                        Disabled = false
                    }).ToList()
                });
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 在系统模块编辑时检查分配给系统模块的按钮，与已授权给各角色的系统模块的按钮是否发生改变
        /// 防止分配给系统模块的按钮与授权按钮不同而引发按钮查询授权失败
        /// </summary>
        /// <param name="moduleId"></param>
        /// <param name="btnIds"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.CheckAssignedButtonsChangeResult)]
        public virtual IActionResult CheckAssignedButtonsChangeResult([FromQuery]int moduleId, [FromBody]List<int> assignedbtnIds)
        {
            var checkResult = CheckAssignedButtonsChange(moduleId, assignedbtnIds);
            if (checkResult.CheckResult)
                return SuccessJson(ApiResponseMessages.SystemModulePageAssignedButtonsChange, new { CheckResult = true });
            else 
                return SuccessJson("", new { CheckResult = false });
        }

        /// <summary>
        /// 系统模块管理-功能模块编辑
        /// </summary>
        /// <param name="changebtnauth">
        /// 当系统模块中已分配至各角色的按钮权限在编辑（修改）中被取消分配时，
        /// 若同意按新的分配方式取消按钮权限分配，则取消所有角色模块中该按钮的权限分配
        /// </param>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.SystemModuleEdit)]
        public virtual IActionResult SystemModuleEditApi([FromQuery]bool changebtnauth, [FromBody]SystemModuleModel model)
        {
            try
            {
                //Model Validate Check
                if (model.ParentModuleId > 0)
                {
                    var parent = _systemModuleModleFactory.GetSystemModuleModel(model.ParentModuleId);
                    if (parent == null) throw new PMSException(ApiResponseMessages.ParenIdNotFound, SystemLogLevel.Error);
                    model.ModuleDepth = parent.ModuleDepth + 1;
                }
                else model.ModuleDepth = 1;

                if (model.ModuleAssignedButtonIds == null)
                    model.ModuleAssignedButtonIds = new List<int>();
                if (model.OpenMode == LinkOpenMode.None)
                {
                    model.ModuleAssignedButtonIds.Clear();
                    model.RouteUrl = string.Empty;
                }
                if (model.LimitedStoreIds == null)
                    model.LimitedStoreIds = new List<int>();

                var entity = model.ToEntity<SystemModule>();
                entity.LimitedToStores = model.LimitedStoreIds.Count > 0;
                entity.UpdatedOnTimeUtc = DateTime.UtcNow;
                if (entity.Id == 0) //Insert
                {
                    entity.CreatedOnTimeUtc = entity.UpdatedOnTimeUtc;
                    entity = _systemModuleService.InsertSystemModule(entity);
                    //新增系统模块时，对所有角色分配模块权限
                    var adminRoleTypes = new RoleType[] { RoleType.Administrator, RoleType.BackendUser };
                    var adminRoles = from role in _customerService.GetAllCustomerRoles()
                                     where adminRoleTypes.Contains(role.RoleType)
                                     select role;
                    adminRoles.ToList().ForEach(role =>
                    {
                        var mapping = new SystemModuleCustomerRoleMapping();
                        if(role.RoleType == RoleType.Administrator)
                        {//系统管理员自动对模块及对模块分配的按钮拥有使用权限
                            mapping.ViewPermission = true;
                            mapping.AuthorizedButtons = entity.ModuleButtonIds;
                        }
                        else
                        {
                            mapping.ViewPermission = false;
                            mapping.AuthorizedButtonIds = null;
                        }
                        mapping.SystemModuleId = entity.Id;
                        mapping.CustomerRoleId = role.Id;
                        _systemModuleService.AddSystemModuleCustomerRoleMapping(mapping);
                    });
                }
                else
                {
                    var checkResult = CheckAssignedButtonsChange(entity.Id, entity.ModuleButtonIds);
                    if (changebtnauth && checkResult.CheckResult)
                    {
                        var allRolesModuleMappings = _systemModuleService.GetSystemModuleCustomerRoleMappingsBySystemModuleId(entity.Id);
                        allRolesModuleMappings.ToList().ForEach(mp =>
                        {
                            mp.AuthorizedButtons = mp.AuthorizedButtons.Except(checkResult.CanceledBtnIds).ToList();
                            _systemModuleService.UpdatedSystemModuleCustomerRoleMapping(mp);
                        });
                    }
                    _systemModuleService.UpdateSystemModule(entity);
                }

                var moduleMappings = _storeMappingService.GetStoreMappings(entity);
                if (moduleMappings?.Any() ?? false)
                {
                    if (!CommonHelper.ArraysEqual(model.LimitedStoreIds.ToArray(), moduleMappings.Select(m => m.StoreId).ToArray()))
                    {
                        var mapsToDelete = moduleMappings.Where(x => !model.LimitedStoreIds.Contains(x.StoreId)).ToList();
                        mapsToDelete.ForEach(m =>
                        {
                            _storeMappingService.DeleteStoreMapping(m);
                        });
                        var idsToInsert = model.LimitedStoreIds.Where(x => !moduleMappings.Select(m => m.StoreId).Contains(x)).ToList();
                        idsToInsert.ForEach(sid =>
                        {
                            _storeMappingService.InsertStoreMapping(entity, sid);
                        });
                    }
                }
                else
                {
                    model.LimitedStoreIds.ToList().ForEach(storeid => {
                        _storeMappingService.InsertStoreMapping(entity, storeid);
                    });
                }

                return SuccessJson(ApiResponseMessages.ModelUpdateSuccess);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 系统模块权限管理-按角色获取角色对应的系统模块权限数据
        /// </summary>
        /// <param name="roleId"></param>
        /// <returns></returns>
        [HttpGet(WebApiRouteConfig.GetSystemModuleListsWithAuthorizeByAdminRole)]
        public IActionResult GetSystemModuleListsWithAuthorizeByAdminRole(int roleId)
        {
            try
            {
                var curStore = _storeContext.CurrentStore;
                var adminRole = _customerService.GetCustomerRoleById(roleId);
                if (adminRole == null)
                    throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "用户角色"), SystemLogLevel.Error);
                else if (adminRole.RoleType != RoleType.Administrator && adminRole.RoleType != RoleType.BackendUser)
                    throw new PMSException(ApiResponseMessages.NotBackendAdmin, SystemLogLevel.Error);
                var modules = _systemModuleService.GetSysteModulesByRole(adminRole, curStore, true);
                var moduleroleMappings = _systemModuleService.GetSystemModuleCustomerRoleMappingsByCustomerRole(adminRole);
                bool skipCheckEmpty = adminRole.RoleType == RoleType.Administrator
                                  ? true 
                                  : (modules?.Any() ?? false) || (moduleroleMappings?.Any() ?? false);
                if (skipCheckEmpty)
                {
                    var moduleModels = new List<SystemModuleModel>();
                    modules.ToList().ForEach(m =>
                    {
                        var model = m.ToModel<SystemModuleModel>();
                        if (adminRole.RoleType == RoleType.Administrator)
                        {
                            //1: 借用IsActive字段存储是否模块是否拥有操作权限
                            //2：系统管理员拥有所有功能权限
                            model.IsActive = true;
                            model.ModuleAuthorizedButtonIds = model.ModuleAssignedButtonIds;
                            moduleModels.Add(model);
                        }
                        else
                        {
                            var mp = moduleroleMappings.FirstOrDefault(mp => mp.SystemModuleId == m.Id);
                            if (mp != null)
                            {
                                model.IsActive = mp.ViewPermission;
                                model.ModuleAuthorizedButtonIds = mp.AuthorizedButtons;
                                moduleModels.Add(model);
                            }
                        }
                    });
                    return SuccessJson("", new
                    {
                        ModuleModels = moduleModels,
                        ModuleButtons = _systemModuleModleFactory.PrepareAllModuleButtons(),
                    });
                }
                throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "用户角色对应系统模块"), SystemLogLevel.Warning);
            }
            catch (PMSException pex)
            {
                return pex.LogLevel switch
                {
                    SystemLogLevel.Warning => WarnJson(pex.Message),
                    _ => ErrorJson(pex.Message)
                };
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }

        /// <summary>
        /// 更新用户角色对应系统模块的操作权限
        /// </summary>
        /// <param name="buttonId">for permission use</param>
        /// <param name="moduleId">for permission use</param>
        /// <param name="roleId"></param>
        /// <param name="authorizeList"></param>
        /// <returns></returns>
        [HttpPost(WebApiRouteConfig.UpdateSystemModuleAuthorize)]
        public IActionResult UpdateSystemModuleAuthorizeApi([FromQuery]int buttonId, [FromQuery]int moduleId, [FromQuery]int roleId, [FromBody]List<SystemModuleModel> authorizeList)
        {
            try
            {
                if (!_permissionService.AdminModuleButtonAuthorize(moduleId, buttonId))
                    throw new PMSException(ApiResponseMessages.UnAuthorizedPermission, SystemLogLevel.Error);
                if (roleId <= 0 || (!authorizeList?.Any() ?? true))
                    throw new PMSException(ApiResponseMessages.ArgumentCannotBeNull);
                var customerRole = _customerService.GetCustomerRoleById(roleId);
                if (customerRole == null) throw new PMSException(string.Format(ApiResponseMessages.EntityNotFound, "用户角色"), SystemLogLevel.Error);
                if (customerRole.RoleType == RoleType.Administrator)
                {//系统管理员无论前端如何修改都全量保存所有权限
                    authorizeList.ForEach(model => 
                    {
                        //借用IsActive字段存储是否模块是否拥有操作权限
                        model.IsActive = true;
                        model.ModuleAuthorizedButtonIds = model.ModuleAssignedButtonIds;
                    });
                }
                var updateList = new List<SystemModuleCustomerRoleMapping>();
                foreach (var moduleModel in authorizeList)
                {
                    var mapping = new SystemModuleCustomerRoleMapping();
                    //参见GetSystemModuleListsWithAuthorizeByAdminRole()字段借用存储
                    mapping.ViewPermission = moduleModel.IsActive;
                    mapping.AuthorizedButtonIds = ConvertFromArray(moduleModel.ModuleAuthorizedButtonIds);
                    mapping.SystemModuleId = moduleModel.Id;
                    mapping.CustomerRoleId = customerRole.Id;
                    updateList.Add(mapping);
                }
                _systemModuleService.UpdateSystemModuleCustomerRoleMappingsWithSameCustomerRole(customerRole, updateList);
                updateList.Clear();
                return SuccessJson(ApiResponseMessages.ModelUpdateSuccess);
            }
            catch (Exception ex)
            {
                return ErrorJson(ex.Message);
            }
        }
        #endregion
    }
}
